package com.wyw.hemerocallis.service.comunication;

import com.alibaba.fastjson.JSON;
import com.netflix.loadbalancer.*;
import com.netflix.loadbalancer.reactive.LoadBalancerCommand;
import com.wyw.hemerocallis.constant.CommonConstant;
import com.wyw.hemerocallis.vo.JwtToken;
import com.wyw.hemerocallis.vo.UsernameAndPassword;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import rx.Observable;

/**
 * 使用 Ribbon 实现微服务通信
 *
 * @author Mr Wu    yewen.wu.china@gmail.com
 * <p>
 * Update History:
 * Author        Time            Content
 */
@Slf4j
@Service
public class UseRibbonService {

    private final RestTemplate restTemplate;
    private final DiscoveryClient discoveryClient;
    public UseRibbonService(RestTemplate restTemplate, DiscoveryClient discoveryClient) {
        this.restTemplate = restTemplate;
        this.discoveryClient = discoveryClient;
    }

    /**
     * 通过 Ribbon 调用 Authority 服务获取 Token
     */
    public JwtToken getTokenFormAuthorityServiceByRibbon(UsernameAndPassword usernameAndPassword) {
        // 注意url中的ip和端口换成服务名称
        String requestUrl = String.format(
                "http://%s/hemerocallis-authority-center/authority/token",
                CommonConstant.AUTHORITY_CENTER_SERVICE_ID
        );
        log.info("login request url and body: {}, {}", requestUrl,
                JSON.toJSONString(usernameAndPassword));

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        // 这里一定要使用自己注入的 RestTemplate
        return restTemplate.postForObject(
                requestUrl,
                new HttpEntity<>(JSON.toJSONString(usernameAndPassword), headers),
                JwtToken.class
        );
    }

    /**
     * 使用原生的Ribbon Api，看看Ribbon如何完成的：服务调用+负载均衡
     * @param usernameAndPassword
     * @return
     */
    public JwtToken thinkInRibbon(UsernameAndPassword usernameAndPassword) {
        String urlFormat = "http://%s/hemerocallis-authority-center/authority/token";

        //通过注册中心找到服务提供方的地址和端口号
        List<ServiceInstance> targetInstances = discoveryClient.getInstances(
                CommonConstant.AUTHORITY_CENTER_SERVICE_ID
        );

        //构造Ribbon服务列表
        List<Server> servers = new ArrayList<>(targetInstances.size());
        targetInstances.forEach(i -> {
            servers.add(new Server(i.getHost(), i.getPort()));
            log.info("发现目标instance:[{}] - > [{}]", i.getHost(), i.getPort());
        });

        //2、使用负载均衡策略实现远端服务调用
        //构建Ribbon负载实例
        BaseLoadBalancer loadBalancer = LoadBalancerBuilder.newBuilder()
                .buildFixedServerListLoadBalancer(servers);

        //设置负载均衡策略
        loadBalancer.setRule(new RetryRule(new RandomRule(), 300));

        String result = LoadBalancerCommand.builder()
                .withLoadBalancer(loadBalancer)
                .build().submit( server -> {
                    String targetUrl = String.format(urlFormat, String.format("%s:%s", server.getHost(), server.getPort()));
                    log.info("target request url: [{}]", targetUrl);

                    HttpHeaders httpHeaders = new HttpHeaders();
                    httpHeaders.setContentType(MediaType.APPLICATION_JSON);

                    String tokenStr = new RestTemplate().postForObject(targetUrl,
                            new HttpEntity<>(JSON.toJSONString(usernameAndPassword), httpHeaders), String.class);
                    return Observable.just(tokenStr);
                        }).toBlocking().first().toString();
        return JSON.parseObject(result, JwtToken.class);
    }
    

}
